home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / pluginy Firefox / 52811 / 52811.xpi / chrome / content / AES / jscrypt.js < prev    next >
Encoding:
JavaScript  |  2009-08-23  |  8.3 KB  |  296 lines

  1.  
  2. //            JavaScrypt  --  Main page support functions
  3.  
  4. //        For details, see http://www.fourmilab.ch/javascrypt/
  5.  
  6. var loadTime = (new Date()).getTime();  // Save time page was loaded
  7. var key;                                // Key (byte array)
  8. var prng;                                // Pseudorandom number generator
  9.     
  10. //    setKey  --  Set key from string or hexadecimal specification 
  11. function setKey(pwd,tipo_pwd_enc) {
  12.     if (tipo_pwd_enc[0].selected==true) { //Text key
  13.         var s = encode_utf8(pwd.value); //ritorna la password codificata come utf-8
  14.       var i, kmd5e, kmd5o;
  15.  
  16.       if (s.length == 1) {
  17.           s += s; //se la password ha un solo carattere, lo raddoppio
  18.       }
  19.       
  20.       md5_init();
  21.       for (i = 0; i < s.length; i += 2) {
  22.           md5_update(s.charCodeAt(i));
  23.       }
  24.       md5_finish(); //calcola md5 di una parte della password
  25.       kmd5e = byteArrayToHex(digestBits);
  26.       
  27.       md5_init();
  28.       for (i = 1; i < s.length; i += 2) {
  29.           md5_update(s.charCodeAt(i));
  30.       }
  31.       md5_finish();
  32.       kmd5o = byteArrayToHex(digestBits);
  33.       
  34.       var hs = kmd5e + kmd5o;
  35.       key =  hexToByteArray(hs);
  36.       hs = byteArrayToHex(key);
  37.     } 
  38.   else if (tipo_pwd_enc[1].selected==true){            // Hexadecimal key
  39.     var s = pwd.value;
  40.     var hexDigits = "0123456789abcdefABCDEF";
  41.       var hs = "", i, bogus = false;
  42.  
  43.       for (i = 0; i < s.length; i++) {
  44.           var c = s.charAt(i);
  45.           if (hexDigits.indexOf(c) >= 0) {
  46.                 hs += c;
  47.           } 
  48.       else {
  49.             bogus = true;
  50.           }
  51.       }
  52.       if (bogus) {
  53.             alert(strBundle.getString('jscryptSetKeyErrMessage'));
  54.       }
  55.       if (hs.length > (keySizeInBits / 4)) {
  56.             alert(strBundle.getFormattedString("jscryptSetKeyErrMessage2", [ (keySizeInBits / 4) ]));
  57.             pwd.value = hs = hs.slice(0, 64);
  58.       } 
  59.     else {
  60.             //  If key is fewer than 64 hex digits, fill it with zeroes
  61.             while (hs.length < (keySizeInBits / 4)) {
  62.               hs += "0";
  63.             }
  64.     }
  65.       key =  hexToByteArray(hs);
  66.   }
  67. }
  68.     
  69. /*    Generate a key from the pseudorandom number generator
  70. and stuff it in the key field.  The kind of key generated
  71. (text or hexadecimal) is determined by which box is checked
  72. below the key field.  */
  73.     
  74. function Generate_key(tipo_pwd_enc) {
  75.     var i, j, k = "";
  76.  
  77.     var i, j, k = "";
  78.  
  79.   addEntropyTime();
  80.   var seed = keyFromEntropy();
  81.  
  82.     var prng = new AESprng(seed);
  83.   if (tipo_pwd_enc[0].selected) {
  84.     //    Text key
  85.     var charA = ("A").charCodeAt(0);
  86.   
  87.     for (i = 0; i < 12; i++) {
  88.       if (i > 0) {
  89.           k += "-";
  90.       }
  91.       for (j = 0; j < 5; j++) {
  92.           k += String.fromCharCode(charA + prng.nextInt(25));
  93.       }
  94.     }
  95.   } 
  96.   else {
  97.     // Hexadecimal key
  98.     var hexDigits = "0123456789ABCDEF";
  99.   
  100.     for (i = 0; i < 64; i++) {
  101.        k += hexDigits.charAt(prng.nextInt(15));
  102.     }
  103.   }
  104.     delete prng;
  105.     return k;
  106. }
  107.  
  108. //Encrypt the text    
  109. function Encrypt_text(pwd,body,tipo_pwd_enc) {
  110.     var v, i;
  111.     var prefix = strBundle.getFormattedString("encryptMessagePrefix", [ "AES", "#####" ]),
  112.         suffix = strBundle.getFormattedString("encryptMessageSuffix", [ "#####" ]);
  113.     
  114.   if (pwd.value.length == 0) {
  115.         alert(strBundle.getString('pwdErrorMessage'));
  116.         return;
  117.     }
  118.   if (body.length == 0) {
  119.         alert(strBundle.getString('jscryptEncryptTextErrMessage'));
  120.         return;
  121.     }
  122.   setKey(pwd,tipo_pwd_enc);
  123.  
  124.     addEntropyTime();
  125.   prng = new AESprng(keyFromEntropy());
  126.     var plaintext = encode_utf8(body);
  127.     
  128.     //  Compute MD5 sum of message text and add to header
  129.     md5_init();
  130.     for (i = 0; i < plaintext.length; i++) {
  131.         md5_update(plaintext.charCodeAt(i));
  132.     }
  133.     md5_finish();
  134.     var header = "";
  135.     for (i = 0; i < digestBits.length; i++) {
  136.         header += String.fromCharCode(digestBits[i]);
  137.     }
  138.     
  139.     //  Add message length in bytes to header
  140.     i = plaintext.length;
  141.     header += String.fromCharCode(i >>> 24);
  142.     header += String.fromCharCode(i >>> 16);
  143.     header += String.fromCharCode(i >>> 8);
  144.     header += String.fromCharCode(i & 0xFF);
  145.  
  146.     /*  The format of the actual message passed to rijndaelEncrypt is:
  147.   
  148.       Bytes       Content
  149.      0-15       MD5 signature of plaintext
  150.     16-19       Length of plaintext, big-endian order
  151.     20-end      Plaintext
  152.     
  153.   Note that this message will be padded with zero bytes
  154.   to an integral number of AES blocks (blockSizeInBits / 8).
  155.   This does not include the initial vector for CBC
  156.   encryption, which is added internally by rijndaelEncrypt.
  157.   */
  158.  
  159.     var ct = rijndaelEncrypt(header + plaintext, key, "CBC");
  160.  
  161.   if (tipo_pwd_enc[2].selected) {
  162.         v = armour_codegroup(ct);
  163.     } 
  164.   else if (tipo_pwd_enc[3].selected) {
  165.         v = armour_hex(ct);
  166.     } 
  167.   else if (tipo_pwd_enc[4].selected) {
  168.         v = armour_base64(ct);
  169.     }    
  170.   delete prng;
  171.   return prefix + v + suffix;
  172. }
  173.  
  174. /*  Examine the message and determine which kind of ASCII
  175. armour it uses from the sentinel preceding the message.
  176. We test for each of the sentinels and, if any are
  177. found, decide based on the one found first in the
  178. message (since, for example, the sentinel for
  179. codegroup armour might appear in a Base64 message,
  180. but only after the Base64 sentinel).  If none of
  181. the sentinels are found, we decode using the armour
  182. type specified by the checkboxes for encryption.
  183. The return value is an integer which identifies the armour type as follows:
  184.     
  185.       0   Codegroup
  186.         1   Hexadecimal
  187.         2   Base 64  */
  188. function determineArmourType(s,tipo_pwd_enc) {
  189.   var kt, pcg, phex, pb64, pmin;
  190.     
  191.     pcg = s.indexOf(codegroupSentinel);
  192.     phex = s.indexOf(hexSentinel);
  193.     pb64 = s.indexOf(base64sent);
  194.     if (pcg == -1) {
  195.         pcg = s.length;
  196.     }
  197.     if (phex == -1) {
  198.         phex = s.length;
  199.     }
  200.     if (pb64 == -1) {
  201.         pb64 = s.length;
  202.     }
  203.     pmin = Math.min(pcg, Math.min(phex, pb64));
  204.     if (pmin < s.length) {
  205.         if (pmin == pcg) {
  206.             kt = 0;
  207.         } else if (pmin == phex) {
  208.             kt = 1;
  209.         } else {
  210.             kt = 2;
  211.         }
  212.     } 
  213.   else {
  214.         if (tipo_pwd_enc[2].checked) {
  215.             kt = 0;
  216.         } 
  217.       else if (tipo_pwd_enc[3].checked) {
  218.             kt = 1;
  219.         } 
  220.       else if (tipo_pwd_enc[4].checked) {
  221.             kt = 2;
  222.         }
  223.     }
  224.     return kt;
  225. }
  226.     
  227. //    Decrypt ciphertext with key, place result in plaintext field
  228. function Decrypt_text(pwd,body,tipo_pwd_enc) {
  229.     
  230.   if (pwd.value.length == 0) {
  231.         alert(strBundle.getString('pwdErrorMessage'));
  232.         return;
  233.     }
  234.   if (body.length == 0) {
  235.         alert(strBundle.getString('jscryptDecryptTextErrMessage'));
  236.         return;
  237.     }
  238.     
  239.   setKey(pwd,tipo_pwd_enc);
  240.     var ct = new Array(), kt;
  241.     kt = determineArmourType(body,tipo_pwd_enc);
  242.   if (kt == 0) {
  243.             ct = disarm_codegroup(body);
  244.     } else if (kt == 1) {
  245.             ct = disarm_hex(body);
  246.     } else if (kt == 2) {
  247.             ct = disarm_base64(body);
  248.     }
  249.  
  250.     var result = rijndaelDecrypt(ct, key, "CBC");
  251.     
  252.     var header = result.slice(0, 20);
  253.     result = result.slice(20);
  254.     
  255.     /*  Extract the length of the plaintext transmitted and
  256.     verify its consistency with the length decoded.  Note
  257.     that in many cases the decrypted messages will include
  258.     pad bytes added to expand the plaintext to an integral
  259.     number of AES blocks (blockSizeInBits / 8).  */
  260.     
  261.     var dl = (header[16] << 24) | (header[17] << 16) | (header[18] << 8) | header[19];
  262.   if ((dl < 0) || (dl > result.length)) {
  263.       alert(strBundle.getFormattedString("jscryptDecryptErrMessage", [ dl , result.length ]));            
  264.           //    Try to sauve qui peut by setting length to entire message
  265.           dl = result.length;
  266.     }
  267.     
  268.     /*  Compute MD5 signature of message body and verify
  269.   against signature in message.  While we're at it,
  270.   we assemble the plaintext result string.  Note that
  271.   the length is that just extracted above from the
  272.   message, *not* the full decrypted message text.
  273.   AES requires all messages to be an integral number
  274.   of blocks, and the message may have been padded with
  275.   zero bytes to fill out the last block; using the
  276.   length from the message header elides them from
  277.   both the MD5 computation and plaintext result.  */
  278.         
  279.     var i, plaintext = "";
  280.     
  281.     md5_init();
  282.     for (i = 0; i < dl; i++) {
  283.         plaintext += String.fromCharCode(result[i]);
  284.         md5_update(result[i]);
  285.     }
  286.     md5_finish();
  287.  
  288.     for (i = 0; i < digestBits.length; i++) {
  289.         if (digestBits[i] != header[i]) {
  290.             alert(strBundle.getString('jscryptDecryptErrMessage2'));
  291.         break;
  292.         }
  293.     }
  294.     //  That's it; plug plaintext into the result field
  295.     return decode_utf8(plaintext);
  296. }